#pragma once

#include <cstdint>
#include <cstring>
#include <vector>
#include <string>
#include "ikcp.h"

#pragma pack(push, 1)
struct Address {
	uint32_t ip;   // 网络字节序
	uint16_t port; // 网络字节序
};
struct Message {
	uint8_t  magic;
	uint8_t  flag;
	Address  routers[4];
	uint16_t payload_len;
	char    *payload_data;

	Message() : magic(0), flag(0), payload_len(0), payload_data(nullptr) { memset(routers, 0, sizeof(routers)); }

	~Message() { delete[] payload_data; }

	// 序列化为字节流
	std::vector<uint8_t> serialize() const {
		std::vector<uint8_t> data(sizeof(magic) + sizeof(flag) + sizeof(routers) + sizeof(payload_len) + payload_len);
		size_t               offset = 0;
		data[offset++]              = magic;
		data[offset++]              = flag;
		memcpy(data.data() + offset, routers, sizeof(routers));
		offset += sizeof(routers);
		uint16_t plen = htons(payload_len);
		memcpy(data.data() + offset, &plen, sizeof(plen));
		offset += sizeof(plen);
		if (payload_data && payload_len > 0) {
			memcpy(data.data() + offset, payload_data, payload_len);
		}
		return data;
	}

	// 从字节流反序列化
	static Message deserialize(const uint8_t *data, size_t len) {
		Message msg;
		size_t  offset = 0;
		msg.magic      = data[offset++];
		msg.flag       = data[offset++];
		memcpy(msg.routers, data + offset, sizeof(msg.routers));
		offset += sizeof(msg.routers);
		uint16_t plen;
		memcpy(&plen, data + offset, sizeof(plen));
		msg.payload_len = ntohs(plen);
		offset += sizeof(plen);
		if (msg.payload_len > 0 && offset + msg.payload_len <= len) {
			msg.payload_data = new char[msg.payload_len];
			memcpy(msg.payload_data, data + offset, msg.payload_len);
		} else {
			msg.payload_data = nullptr;
		}
		return msg;
	}
};
#pragma pack(pop)

class KCPConnection {
public:
	KCPConnection(uint32_t conv, int sockfd, struct sockaddr_in peer_addr);
	~KCPConnection();

	// 发送Message
	bool sendMessage(const Message &msg);

	// 接收Message
	bool recvMessage(Message &msg);

	// 定期更新KCP
	void update();

	// 处理输入的UDP数据包
	void input(const uint8_t *data, int len);

	// 获取下次需要update的时间
	uint32_t check();

private:
	static int kcp_output(const char *buf, int len, ikcpcb *kcp, void *user);

	ikcpcb            *kcp_;
	int                sockfd_;
	struct sockaddr_in peer_addr_;
};
